<?php

/**
 * Post-validator pentru formularul principal.
 *
 * Se verifica daca totalul sumelor distribuite la fiecare apartament este egal cu valoarea cheltuielii
 */
class CriteriuFormBeneficiarPostValidator extends sfValidatorSchema
{
    const INVALID_APARTAMENT_IDS = 'invalid_apartamente';
    const INCORRECT_SUM         = 'incorrect_sum';

    const DIFF = 'diff';

    protected function configure($options = array(), $messages = array())
    {
        parent::configure($options, $messages);

        $this->addMessage(self::INVALID_APARTAMENT_IDS, 'Apartamentele alese sunt invalide.');
        $this->addMessage(self::INCORRECT_SUM, 'Diferenţa dintre suma valorilor repartizate şi valoarea cheltuielii este de %'.self::DIFF.'% lei.');
    }

    /**
     * @param array $values Valorile din formularul principal
     */
    protected function doClean($values)
    {
        $errorSchema = new sfValidatorErrorSchema($this);

        // test if the apartment ids are valid
        if (! $this->checkApartamentIds($values[CheltuialaForm::TARGET], $this->extractExtra($values, CriteriuFormBeneficiar::APARTAMENT_ID)))
        {
            $error = new sfValidatorError($this, self::INVALID_APARTAMENT_IDS);
            $errorSchema->addError($error);
        }

        // test if the sum of apartment values equals the invoice value
        if ($diff = $this->checkSum($values))
        {
            $error = new sfValidatorError($this, self::INCORRECT_SUM, array(self::DIFF => $diff));
            $errorSchema->addError($error);
        }

        // if there are errors, throw the error exception
        if ($errorSchema->count())
        {
            throw $errorSchema;
        }

        return $values;
    }

    /**
     * Extrage ID-urile apartamentelor sau valorile repartizate la acestea
     * @param array $values Reprezinta valorile corespunzatoare formularului suplimentar
     * @return array
     */
    protected function extractExtra(array $values, $field)
    {
        $elements = array();
        if (isset($values[CriteriuForm::NAME]))
        {
            foreach ($values[CriteriuForm::NAME] as $element)
            {
                $elements[] = $element[$field];
            }
        }

        return $elements;
    }

    /**
     * Verifica daca ID-urile apartamentelor din formularul suplimentar coincid cu ID-urile apartamentelor selectate
     *
     * @param array $target Lista cu ID-urile apartamentelor selectate
     * @param array $extra  ID-urile apartamentelor din formularul suplimentar
     */
    protected function checkApartamentIds(array $target, array $extra)
    {
        sort($target);
        sort($extra);

        $check = (array_values($target) == array_values($extra));

        return $check;
    }

    /**
     * Verifica daca suma valorilor distribuite la apartamente este egala cu valoarea cheltuielii
     *
     * @param array $values Lista cu valori, asa cum provine din formularul principal
     * @return int Diferenta dintre suma valorilor si valoare cheltuielii
     */
    protected function checkSum(array $values)
    {
        // valoarea cheltuielii
        $invoiceValue = $values[CheltuialaForm::VALOARE];

        // daca valoarea cheltuielii nu este specificata sau nu este valida, acest test este ignorat
        if (!$invoiceValue)
        {
            return 0;
        }

        // suma valorilor distribuite la apartamente
        $apartamentValues = $this->extractExtra($values, CriteriuFormBeneficiar::APARTAMENT_VALUE);
        $sum = array_sum($apartamentValues);

        $diff = $sum - $invoiceValue;

        return $diff;
    }

}
